package com.guchenbo.example.lock;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;

/**
 * java的fork/join框架的测试用例
 * fork/join框架，
 * fork 将一个大任务分割成数个子任务，由数个线程执行，
 * join 将数个子任务的运行结果合并成最终结果
 * <p/>
 * Created by CreGu on 2016/6/21.
 */
public class TestForkJoin {

    public void withForkJoin() {
        long t1 = System.currentTimeMillis();
        CountTask countTask = new CountTask(1, 10);
        ForkJoinPool forkJoinPool = new ForkJoinPool();
        try {
            int result = forkJoinPool.submit(countTask).get();
            System.out.println(result);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        long t2 = System.currentTimeMillis();
        System.out.printf("使用fork/join，耗时%s\n", (t2 - t1));
    }

    public void withoutForkJoin() {
        long t1 = System.currentTimeMillis();
        NonCountTask nonCountTask = new NonCountTask(1, 10);

        int result = nonCountTask.compute();
        System.out.println(result);

        long t2 = System.currentTimeMillis();
        System.out.printf("没有使用fork/join，耗时%s\n", (t2 - t1));
    }

    public static void main(String[] args) {
        TestForkJoin test = new TestForkJoin();
        test.withForkJoin();
        test.withoutForkJoin();
    }

    /**
     * 计算连加，如1+2+3+4+5
     * 这里使用的阀值太小，导致产生了太多的线程，消耗了过多的资源，所以耗时久
     * 这只是一个简单的示例，告诉我fork/join框架是怎么使用的
     */
    static class CountTask extends RecursiveTask<Integer> {
        //        阀值，最多只能计算两个数字
        public static final int THRESHOLD = 2;
        private int start;
        private int end;

        public CountTask(int start, int end) {
            this.start = start;
            this.end = end;
            System.out.printf("创建任务从%s到%s\n", start, end);
        }

        @Override
        protected Integer compute() {
            int num = end - start;
            if (num < THRESHOLD) {
//                少于阀值
                int result = 0;
                for (int i = start; i <= end; i++) {
                    result += i;
                }
                return result;
            } else {
//                多于阀值
//                分成两个子任务
                int middle = (start + end) / 2;
                CountTask leftCountTask = new CountTask(start, middle);
                CountTask rightCountTask = new CountTask(middle + 1, end);
                leftCountTask.fork();
                rightCountTask.fork();

                int leftResult = leftCountTask.join();
                int rightResult = rightCountTask.join();
                return leftResult + rightResult;
            }
        }
    }

    static class NonCountTask {
        private int start;
        private int end;

        public NonCountTask(int start, int end) {
            this.start = start;
            this.end = end;
            System.out.printf("创建任务从%s到%s\n", start, end);
        }

        protected Integer compute() {
            int result = 0;
            for (int i = start; i <= end; i++) {
                result += i;
            }
            return result;
        }
    }
}
